package com.bigflexlib.x.flash.display
{
	
	import com.bigflexlib.x.mx.core.Application.App;
	
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.geom.Point;
	
	/**
	 * 
	 * @author aldo.bucchi@gmail.com
	 * 
	 */	
	public class DisplayListUtil
	{
		
		
		
		
		
		public static function isVisible( dobj:DisplayObject ):Boolean
		{
		
			if ( !dobj.visible )					// it has to be visible
			{
				return false;
			}
			
			
			if ( !dobj.parent )						// and it must have a parent
			{
			
				if ( dobj == App.app.stage ) 		// unless it is the stage
					return true;
			
				return false;		
			}
		
		
			return ( isVisible( dobj.parent ) ); 	// upstream recursion
		
		}
		
		
		
		
		
		
		
		
		
		
		/**
		 * 
		 * Traverses recursively ( getChildAt() ) and returns a flattened list.
		 * Top-down
		 * 
		 * @param node
		 * @param arr
		 * @return 
		 * 
		 */		
		public static function flattenDisplayList( root:DisplayObjectContainer, arr:Array = null ):Array
		{
			if ( arr == null )
				arr = [];
			
			arr.push( root );
			
			var num:int = root.numChildren;
			for ( var i:int=0; i<num; i++ )
			{
				var c:DisplayObjectContainer = root.getChildAt( i ) as DisplayObjectContainer;
				if ( c != null )
				{
					flattenDisplayList( c, arr );
				}
			}
		
			return arr;
			
		}
				
		
		
		
		
		
		
		
		
		/**
		 * 
		 * 
		 * hitTests traversing down the tree.
		 * The first element in the retured array is the element passed as the "container" parameter.
		 * in other words, they are sorted bottom up ( from the lowest depth )
		 * 
		 * if you didn't pass any container, then the first element will be the stage
		 * 
		 * 
		 * @param stagePoint
		 * @param container
		 * @param stack used internally for recursion. don't use it!
		 * @return 
		 * 
		 */		
		public static function getDisplayObjectsUnderStagePoint( stagePoint:Point, container:DisplayObjectContainer = null, stack:Array = null ):Array
		{
			if ( stack == null )
				stack = new Array();
				
			if ( container == null )
			{
				container = App.app.stage;
			}
				
			for ( var i:uint=0; i < container.numChildren ; i++ )
			{
				var child:DisplayObject = container.getChildAt( i );
				
				if ( child.hitTestPoint( stagePoint.x, stagePoint.y ) )
				{
					stack.push( child );
				
					if ( child is DisplayObjectContainer )
					{
						getDisplayObjectsUnderStagePoint( stagePoint, child as DisplayObjectContainer, stack  );
					}			
				
				}
				
			}
		
			return stack;
		}
		
		
		
		/**
		 * 
		 * Similar to getDisplayObjectsUnderStagePoint() but will return the stack sliced into substacks
		 * substacks start at every top level container ( all those parented directly by SystemManager ).
		 * That is, every popup, tooltip, etc
		 * 
		 * A common use is to get all the underlying objects of the topmost popup, then access
		 * the last element returned by this function, which will be the array you are looking for, starting
		 * in the container itself ( popup )
		 * 
		 * This is usually what you want ( more on this... )
		 * 
		 * 
		 * @param stack
		 * @return 
		 * 
		 */		 
		public static function groupDisplayObjectsByTopLevelContainer( stack:Array ):Array
		{
			var groups:Array = [];
			
			groups.push( [] );
			
			for ( var i:uint=0; i < stack.length; i++ )
			{
				// in which group are we??
				if ( i > 0 ) // skip the root or we might end up with an empty first group
					if ( stack[ i ] is DisplayObjectContainer )
						// it is a container...
						if ( ( stack[ i ] as DisplayObjectContainer ).parent == App.app.systemManager )
							// and it is a top level object. let's create a new group.
							groups.push( [] );

				( groups[ groups.length - 1 ] as Array ).push( stack[ i ] );

			}
			
			return groups;
			
		}		
		
		




		/*
		// TODO: test
		public static function getDisplayObjectsByAbsoluteZ_recursive( container:DisplayObjectContainer = null, stack:Array = null ):Array
		{

			if ( stack == null )
				stack = new Array();
				
			var container:DisplayObjectContainer = App.app.stage;
				
			for ( var i:uint=0; i < container.numChildren ; i++ )
			{
				var child:DisplayObject = container.getChildAt( i );
				
				stack.push( child );
				
				if ( child is DisplayObjectContainer )
				{
					getDisplayObjectsByAbsoluteZ_recursive( child as DisplayObjectContainer, stack  );
				}			
				
			}
		
			return stack;						
					
		}
		*/







		
		
				
		public static function traceDisplayList( container:DisplayObjectContainer, indentString:String = "" ):void
		{
		    var child:DisplayObject;
		    for ( var i:uint=0 ; i < container.numChildren ; i++ )
		    {
				child = container.getChildAt(i);
				
		        trace( indentString , child , child.name );

				if ( container.getChildAt( i ) is DisplayObjectContainer )
				{
					traceDisplayList( DisplayObjectContainer( child ) , indentString + "    " );
				}
		    }
		}

		
	}
	
}